home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / archiver / pdtar.zip / DOSIO.C < prev    next >
C/C++ Source or Header  |  1988-03-06  |  6KB  |  296 lines

  1. /*
  2.  * Dos direct-disk I/O routines for PDTAR
  3.  * By E. Roskos 2/88
  4.  * For Minix-compatible multivolume tar implementation under DOS
  5.  *
  6.  * These routines are based on my Minix "build" I/O code, although
  7.  * changed a lot...
  8.  */
  9.  
  10. #ifdef MSDOS
  11.  
  12. #include <stdio.h>
  13. #include <fcntl.h>
  14. #include <dos.h>
  15.  
  16. extern int physdrv;
  17. extern int devsize;
  18. extern int ftty;
  19. static long curblk = 0;
  20. static int inited = 0;
  21.  
  22. /*
  23.  * Local I/O buffers.  We do the actual disk I/O to one of these two.
  24.  * The reason is that we select which one we'll use, and set iobuf to
  25.  * point to it, in order to get a block of memory that doesn't cross
  26.  * a 64K boundary -- because the DMA controller can't do I/O across
  27.  * a 64K boundary. 
  28.  */
  29. static char buf1[512], buf2[512];
  30. static char *iobuf;
  31.  
  32. /*
  33.  * DMAoverrun checks whether buff1 crosses a 64K boundary.
  34.  */
  35. static int 
  36. DMAoverrun(buff1)
  37. char *buff1;
  38. {
  39. int i;
  40.  
  41.     i = (int)buff1;
  42.     return(i > i + 512);
  43. }
  44.  
  45. /*
  46.  * absio does absolute disk I/O, using the ROM BIOS
  47.  * It performs BIOS operation "fn", on "drive", specifying
  48.  * block number "blocknr" and buffer "buff" (which must
  49.  * be in the single (small-model) data segment).
  50.  * Note that the block numbering scheme corresponds to the
  51.  * Minix, PC/IX, and DOS 2.x block numbering, not the DOS
  52.  * 3.x block numbering.
  53.  */
  54. static int
  55. absio(fn, drive, blocknr, buff)
  56. int fn;
  57. int drive;
  58. long blocknr;
  59. char *buff;
  60. {
  61. union REGS iregs;
  62. union REGS oregs;
  63. int track;
  64.  
  65.     iregs.h.ah = fn;
  66.     iregs.h.dl = drive;
  67.     track = blocknr / 9;
  68.     iregs.h.dh = track & 1;
  69.     iregs.h.ch = track >> 1;
  70.     iregs.h.cl = (blocknr % 9) + 1;
  71.     iregs.h.al = 1;
  72.     iregs.x.bx = (int)buff;
  73.  
  74.     int86(0x13, &iregs, &oregs);
  75.  
  76.     if (oregs.x.cflag)
  77.     {
  78. #ifdef DEBUGIO
  79.         fprintf(stderr, "absio: error %sing drv %c block %d address %x: bios code %x\n",
  80.             fn==2? "read" : "writ", 'A'+drive, blocknr, buff, oregs.h.ah&0xff);
  81. #endif /* DEBUGIO */
  82.         return(oregs.h.ah&0xff);
  83.     }
  84.     else
  85.     {
  86.         return(0);
  87.     }
  88. }
  89.  
  90. /*
  91.  * initdiskio initializes the floppy disk subsystem and selects
  92.  * a local buffer for us to use, if this is the first time it is
  93.  * called.  Otherwise, it does nothing.
  94.  */
  95. static void
  96. initdskio()
  97. {
  98.     if (!inited)
  99.     {
  100.         absio(0, 0, 0, 0);
  101.         if (DMAoverrun(buf1))
  102.             iobuf = buf2;
  103.         else            
  104.             iobuf = buf1;
  105.         inited++;
  106.     }
  107. }
  108.  
  109. /*
  110.  * absread performs an absolute disk read of "drive"'s block
  111.  * "blocknr", reading into the buffer at "buff".
  112.  */
  113. static int
  114. absread(drive, blocknr, buff)
  115. int drive;
  116. long blocknr;
  117. char *buff;
  118. {
  119. int err;
  120.  
  121.     initdskio();
  122.     err = absio(2, drive, blocknr, iobuf);
  123.     if (!err)
  124.         memcpy(buff, iobuf, 512);
  125.     return(err);    
  126. }
  127.  
  128. /*
  129.  * abswrite performs an absolute disk write of "drive"'s block
  130.  * "blocknr", reading into the buffer at "buff".
  131.  */
  132. static int
  133. abswrite(drive, blocknr, buff)
  134. int drive;
  135. long blocknr;
  136. char *buff;
  137. {
  138. int err;
  139.  
  140.     initdskio();
  141.     memcpy(iobuf, buff, 512);
  142.     return(absio(3, drive, blocknr, iobuf));
  143. }
  144.  
  145. /*
  146.  * physrw reads or writes the data at "buf" for length "len", which
  147.  * must be a multiple of 512 bytes; it reads if fread is 1, or writes
  148.  * if fread is 0.  The data is read/written on the next consecutive
  149.  * block of the floppy disk; if the end of the disk has been reached
  150.  * (as determined by the disk size block count in the global variable
  151.  * devsize) it asks the user to change disks before it performs the I/O,
  152.  * then performs the I/O to block 0 of the new disk. 
  153.  */
  154. static int
  155. physrw(buf, len, fread)
  156. char *buf;
  157. int len;
  158. int fread;
  159. {
  160. int err;
  161. int errct = 0;
  162. int nbytes;
  163. static void diskerr();
  164.  
  165.     nbytes = len; /* save for return value */
  166.     
  167.     /* be sure size of xfer is a multiple of DOS physical block size */
  168.     if (len & 0x1ff)
  169.     {
  170.         fprintf(stderr, "tar: fatal error: phys disk I/O must be ");
  171.         fprintf(stderr, "multiple of 512 bytes\n");
  172.         exit(1);
  173.     }
  174.  
  175.     /* convert byte count to DOS block count */
  176.     len >>= 9;
  177.     
  178.     /* now read or write a block at a time into the buffer */
  179.     while (len > 0)
  180.     {
  181.         /* check for time to change disks */
  182.         if (curblk >= devsize)
  183.         {
  184.             uprintf(ftty, "\ntar: Change disks and press [Enter]: ");
  185.             while (ugetc(ftty)!='\n') ;
  186.             curblk = 0;
  187.         }
  188.  
  189.         /* read or write the next block */
  190.         if (fread)
  191.             err = absread(physdrv, curblk, buf);
  192.         else
  193.             err = abswrite(physdrv, curblk, buf);
  194.  
  195.         /* check for an error */
  196.         if (err)
  197.         {
  198.             diskerr(fread? "reading" : "writing",
  199.                  physdrv, curblk, err);
  200.             errct++;
  201.         }    
  202.         /* increment block number & buf addr, decrement count */
  203.         curblk++;
  204.         buf += 512;
  205.         len--;
  206.     }        
  207.     if (errct)
  208.         return(-1);
  209.     else
  210.         return(nbytes);
  211. }    
  212.  
  213. /*
  214.  * physwrite is the "write" version of physrw, and is what is called
  215.  * from outside this package.  It writes the data at "buf" for
  216.  * length "len", which must be a multiple of 512 bytes, as described
  217.  * above under "physrw".
  218.  */
  219. int
  220. physwrite(buf, len)
  221. char *buf;
  222. int len;
  223. {
  224.     return(physrw(buf, len, 0));
  225. }
  226.  
  227. /*
  228.  * see comments for physwrite
  229.  */
  230. int
  231. physread(buf, len)
  232. char *buf;
  233. int len;
  234. {
  235.     return(physrw(buf, len, 1));    
  236. }
  237.  
  238. /*
  239.  * This routine prints an error message for disk I/O: the operation
  240.  * ("reading", "writing") is in s, the drive number in "drive",
  241.  * the sector number in "sectnum", and the BIOS AH return code
  242.  * is in "err".
  243.  */
  244. static void
  245. diskerr(s,drive,sectnum,err)
  246. int sectnum, err,drive;
  247. char *s;
  248.   extern char *derrtab[];
  249.   char *mp;
  250.   fprintf(stderr, "Error %s drive %c, sector: %d, code: %d = '",
  251.            s, drive+'A',sectnum, err);
  252.   switch (err)
  253.   {
  254.       case 0:
  255.           mp = "No error";
  256.           break;
  257.       case 1:
  258.           mp = "Bad command passed to BIOS";
  259.           break;
  260.       case 2:
  261.           mp = "Address mark not found";
  262.           break;
  263.       case 3:
  264.           mp = "Disk is write protected";
  265.           break;
  266.       case 4:
  267.           mp = "Sector not found";
  268.           break;
  269.       case 8:
  270.           mp = "DMA overrun";
  271.           break;
  272.       case 9:
  273.           mp = "DMA crosses 64K boundary (internal error)";
  274.           break;
  275.       case 0x10:
  276.           mp = "Bad CRC on disk read";
  277.           break;
  278.       case 0x20:
  279.           mp = "Disk controller has failed";
  280.           break;
  281.       case 0x40:
  282.           mp = "Seek failed";
  283.           break;
  284.       case 0x80:
  285.           mp = "No response from controller";
  286.           break;
  287.       default:
  288.           mp = "Unknown error";
  289.          break;
  290.     }
  291.     fprintf(stderr,"%s'\n", mp);                 
  292. }
  293.  
  294. #endif /* MSDOS */
  295.